package fi.aalto.cse.T110_5150.P2PClient;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Logger {
	private static SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");	
	
	/**
	 * Logger levels
	 */
	public static final int DEBUG	= 0x1;
	public static final int INFO	= 0x2;
	public static final int WARNING	= 0x4;
	public static final int ERROR	= 0x8;
	
	/**
	 * Logger types
	 */
	public static final int JOIN			= 0x01;
	public static final int HEART_BEAT		= 0x02;
	public static final int NETWORK_PROBING = 0x04;
	public static final int QUERY			= 0x08;
	public static final int ALL				= 0xFF;
	public static final int NONE			= 0x00;
	
	private static int enabledDebugCategory = P2PHelper.LOGGER_ENABLE_DEGUG;
	
	public static void enableDebug(int category) {
		enabledDebugCategory |= category;
	}
	
	public static void disableDebug(int category) {
		enabledDebugCategory = (enabledDebugCategory & (~category)) & ALL;
	}
	
	public static int getEnabledDebugCategories() {
		return enabledDebugCategory;		
	}
	
	public static String getEnabledDebugCategoryNames() {
		switch (enabledDebugCategory) {
		
		case Logger.NONE:
			return ("none");
			
		case Logger.ALL:
			return ("all");
			
		default:
			StringBuffer buffer = new StringBuffer(); 
			if ((enabledDebugCategory & Logger.JOIN) != 0) {
				buffer.append(" join,");
			}

			if ((enabledDebugCategory & Logger.HEART_BEAT) != 0) {
				buffer.append(" heartbeat,");
			}

			if ((enabledDebugCategory & Logger.NETWORK_PROBING) != 0) {
				buffer.append(" networkprobing,");
			}

			if ((enabledDebugCategory & Logger.QUERY) != 0) {
				buffer.append(" query,");
			}
			
			return buffer.substring(1, buffer.length() - 1);
		}		
	}

	public static void debug(int category, String message) {
		if ((enabledDebugCategory & category) != 0) {
			internalLog(DEBUG, String.format("[%s] %s", LocalPeer.getInstance(), message));
		}
	}
	
	public static void debugOutputAction(int category, String action, PeerAddress remotePeerAddress) {
		if ((enabledDebugCategory & category) != 0) {
			internalLog(DEBUG, String.format("[%s -> %s] %s", LocalPeer.getInstance(), remotePeerAddress, action));
		}
	}

	public static void debugInputAction(int category, String action, PeerAddress remotePeerAddress) {
		if ((enabledDebugCategory & category) != 0) {
			internalLog(DEBUG, String.format("[%s <- %s] %s", LocalPeer.getInstance(), remotePeerAddress, action));
		}
	}

	public static void info(String message) {
		internalLog(INFO, String.format("[%s] %s", LocalPeer.getInstance(), message));
	}

	public static void infoOutputAction(String action, PeerAddress remotePeerAddress) {
		internalLog(INFO, String.format("[%s -> %s] %s", LocalPeer.getInstance(), remotePeerAddress, action));
	}

	public static void infoInputAction(String action, PeerAddress remotePeerAddress) {
		internalLog(INFO, String.format("[%s <- %s] %s", LocalPeer.getInstance(), remotePeerAddress, action));
	}

	public static void warning(String message) {
		internalLog(WARNING, String.format("[%s] [WARNING] %s", LocalPeer.getInstance(), message));
	}

	public static void warningOutputAction(String action, PeerAddress remotePeerAddress) {
		internalLog(WARNING, String.format("[%s -> %s] [WARNING] %s", LocalPeer.getInstance(), remotePeerAddress, action));
	}

	public static void warningInputAction(String action, PeerAddress remotePeerAddress) {
		internalLog(WARNING, String.format("[%s <- %s] [WARNING] %s", LocalPeer.getInstance(), remotePeerAddress, action));
	}

	public static void error(String message) {
		internalLog(ERROR, String.format("[%s] [ERROR] %s", LocalPeer.getInstance(), message));
	}

	public static void error(Throwable e) {
		error(e.getMessage(), e);
	}	

	public static void error(String message, Throwable e) {
		internalLog(ERROR, String.format("[%s] [ERROR] %s", LocalPeer.getInstance(), message));
		e.printStackTrace();
	}

	private static void internalLog(int level, String s) {
		System.out.printf("%s. %s.%n", dateFormat.format(new Date()), s);
	}
}
